package cn.amossun.starter.event.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.amossun.starter.event.annoation.EventBinding;
import cn.amossun.starter.event.annoation.EventListener;
import cn.amossun.starter.event.annoation.EventQueue;
import cn.amossun.starter.event.common.Constants;
import cn.amossun.starter.event.enums.DurabilityEnum;
import cn.amossun.starter.event.enums.QueueTypeEnum;
import cn.amossun.starter.event.property.EventQueueContext;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public interface ListenerHolder extends ArgumentHolder {

    void processListener(Object bean, String beanName, Method method);

    default EventQueueContext process(EventQueue eventQueue) {
        if (StrUtil.isEmpty(eventQueue.name()) && StrUtil.isEmpty(eventQueue.value())) {
            return null;
        }
        Map<String, Object> argumentsMap = getArguments(eventQueue.arguments());
        EventQueueContext eventQueueContext = new EventQueueContext(
                QueueTypeEnum.CLASSIC,
                eventQueue.name(),
                DurabilityEnum.DURABLE,
                eventQueue.durable(),
                eventQueue.exclusive(),
                eventQueue.autoDelete(),
                argumentsMap
        );
        return eventQueueContext;
    }

    default String getQueueName(Object bean, String beanName, Method method) {
        return String.format(Constants.QUEUE_NAME_TEMPLATE, beanName, method.getName());
    }

    default List<String> getQueueNames(Object bean, String beanName, Method method, EventListener eventListener) {
        String defaultQueueName = getQueueName(bean, beanName, method);
        return buildEventQueueContexts(eventListener, defaultQueueName).stream().map(EventQueueContext::getQueueName).collect(Collectors.toList());
    }

    default List<EventQueueContext> buildEventQueueContexts(EventListener eventListener, String defaultQueueName){
        if(eventListener.queuesToDeclare().length > 0) {
            return Arrays.stream(eventListener.queuesToDeclare()).map(eventQueue -> {
                return process(eventQueue);
            }).collect(Collectors.toList());
        }

        if(eventListener.bindings().length > 0
                && CollectionUtil.isNotEmpty(Arrays.stream(eventListener.bindings()).map(EventBinding::queue).collect(Collectors.toList()))){

            return Arrays.stream(eventListener.bindings()).map(EventBinding::queue).map(eventQueue -> {
                return process(eventQueue);
            }).collect(Collectors.toList());
        }

        Map<String, Object> argumentsMap = getArguments(eventListener.arguments());
        EventQueueContext eventQueueContext = new EventQueueContext(
                QueueTypeEnum.CLASSIC,
                defaultQueueName,
                DurabilityEnum.DURABLE,
                Boolean.TRUE,
                Boolean.FALSE,
                eventListener.autoDelete(),
                argumentsMap);
        return Arrays.asList(eventQueueContext);
    }

}
